# coding: utf-8

import sys, json, struct
from xml.dom import minidom


# ================================================================
# 構造を取得
# ================================================================
f = open("part-struct.json")
PART_STRUCT = json.load(f)
f.close()

# パラメータの展開
for key, part_data in PART_STRUCT.items():
    for i, param in enumerate(part_data):
        # 文字列だった場合, 展開する
        if isinstance(param, str):
            # 文字列要素削除
            del part_data[i]
            # 左右の要素に分ける
            left    = part_data[:i]
            right   = part_data[i:]
            # 文字列タイプに対応するパラメータを代入
            temp = []
            temp.extend( left )
            temp.extend( PART_STRUCT[param] )
            temp.extend( right )
            # 追加
            PART_STRUCT[key] = temp
        
    


# ================================================================
# パート別デフォルトパートデータを生成
# ================================================================
def createDefaultPartData(type):
    # データ
    data = {"name":"nameless"}
    
    # 存在しない場合はpart
    if type not in PART_STRUCT: type = "part"
    # タイプをセット
    data["type"] = type
    # パラメータをセット
    for param in PART_STRUCT[type]:
        key     = param["key"]
        value   = param["value"]
        data[key] = value
        
    
    return data

# ================================================================
# パートデータをバイナリ化
# ================================================================
def partDataToBinary(data):
    
    print("# ================================ ")
    print("# {obj[type]}({obj[name]}) ".format(obj=data) )
    print("# ================================ ")
    
    values = []
    format_list = []
    
    # パーツ別パラメータをバイナリ化
    type = data["type"]
    
    for param in PART_STRUCT[type]:
        key     = param["key"]
        value   = data[key]
        format  = param["format"]
        
        # 値リストに値を追加
        if isinstance(value, list):
            values.extend(value)
        elif isinstance(value, str):
            # utf-8でエンコード
            value = value.encode()
            values.append(value)
        else :
            values.append(value)
        
        # フォーマットリストに追加
        format_list.append(format)
        
    
    # フォーマットリスト文字列
    format_str = '< ' + " ".join(format_list)
    # 構造体を作成
    s = struct.Struct(" ".join(format_list))
    # パック
    packed_data = s.pack(*values)
    # 確認用データ
    conf_data = s.unpack( packed_data )
    
    # ファイルに書きこむ
    f = open("sample.bin", "wb")
    f.write( packed_data )
    f.close()
    
    # 値の表示
    print("values     : ", values)
    print("format_list: ", format_list)
    print("format_str : ", format_str)
    print("packed_data: ", packed_data)
    print("conf_data  : ", conf_data)
    
    return packed_data


# ================================================================
# ルートパートを取得
# ================================================================
def getRootPartElement(element):
    temp = element
    
    while temp.getAttribute("type") != "root":
        temp = temp.parentNode
    
    return temp


# ================================================================
# パスからIDを取得する
# ================================================================
def pathToID(root, path):
    # 空白を削除してリスト化
    path_list = list( map( lambda s:s.strip() , path.split('/') ) )
    # ノード
    node = root
    
    for p in path_list:
        for child in node.childNodes:
            # テキスト, コメントは無視
            if child.nodeType in [child.TEXT_NODE, child.COMMENT_NODE]: continue
            # 名前が一致したらネストする
            if child.getAttribute("name") == p:
                node = child
                break
            
        
    
    return int(node.getAttribute("id"))


# ================================================================
# 文字列から数値リストに変換(コンマ区切り限定)
# ================================================================
def toNumList(str):
    l = str.split(",")
    for i, e in enumerate(l):
        l[i] = int(e)
    
    return l

# ================================================================
# xml element からパーツデータを生成
# ================================================================
def createPartDataFormXML(element):
    # タイプを取得
    type = element.getAttribute("type")
    # タイプに応じたデフォルト値を取得
    data = createDefaultPartData(type)
    # idをセット
    data["id"] = element.getAttribute("id")
    # 名前をセット
    data["name"] = element.getAttribute("name")
    
    # エレメントのパートエレメントを取得する
    root_part_element = getRootPartElement(element)
    
    # xml element でデータを上書き
    for child in element.childNodes:
        # テキスト, コメントノードだった場合はコンティニュー
        if child.nodeType in [child.TEXT_NODE, child.COMMENT_NODE]: continue
        # タグ名別にパラメータを上書き
        tag_name= child.tagName
        value   = child.childNodes[0].data
        # 値に応じて調整
        # 数値配列
        if tag_name in ["pos", "size", "anchor", "rotation"]:
#            data[tag_name] = list( map( int, value.split(",") ) )    # コンマ区切りで分割して数値化
            data[tag_name] = list( int(x) for x in value.split(",") ) # コンマ区切りで分割して数値化
        # 数値
        elif tag_name in ["id", "cols", "rows"]:
            data[tag_name] = int(value)
        # 文字列
        elif tag_name in ["textureName", "typeFile"]:
            data[tag_name] = value
        # イベント
        elif tag_name in ["event0", "event1", "event2"]:
            event_param = value.split(',')
            event_param[0] = int(event_param[0])
            event_param[1] = int(event_param[1])
            
            event_param[2] = pathToID(root_part_element, event_param[2])
            
            data[tag_name] = event_param
    
    return data


# ================================================================
# main時のtest
# ================================================================
def main():
    # xml読み込み
    xdoc = minidom.parse("sample.xml")
    # パートエレメントリストを取得
    elements = xdoc.getElementsByTagName("part")
    
    # パートにユニークなIDを割り振る
    for i, element in enumerate(elements):
        element.setAttribute("id", i)
    
    # パートエレメントをバイナリ化
    for i, element in enumerate(elements):
        data = createPartDataFormXML(element)
        partDataToBinary(data)
    
    pathToID(xdoc.documentElement, "root/sprite0")

# メイン時
if __name__ == '__main__':
    main()





